﻿using MongoDB.Bson;
using MongoDB.Driver;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Entities;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.Synchronization.Interface;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;

namespace Sustainalytics.ClientDW.Synchronization.SyncCarbonData
{
    public class CarbonDataSyncStep : ISyncStep
    {
        private SyncContext _syncContext;

        public SyncStepOrder ExecutionOrder => SyncStepOrder.CarbonData;

        public SyncContext Start(SyncContext syncContext)
        {
            _syncContext = syncContext;
            try
            {
                _syncContext.Token.ThrowIfCancellationRequested();
                _syncContext.Log("Begining carbon data synchronization");

                SyncCarbonData();

                _syncContext.Token.ThrowIfCancellationRequested();
                _syncContext.Log("Ending carbon data synchronization");

                _syncContext.Status = SyncOperationStatus.Succeeded;
            }
            catch (Exception ex)
            {
                _syncContext.Log("Carbon Data Sync Step failed:" + ex);
            }

            return _syncContext;
        }

        private void SyncCarbonData()
        {
            var carbonData = ReadCarbonData();

            SaveCarbonData(carbonData);
        }

        private List<CarbonData> ReadCarbonData()
        {
            var sw = Stopwatch.StartNew();

            var repository = GetCarbonDataSqlRepository();

            var carbonData = repository.GetCarbonData();

            sw.Stop();

            _syncContext.Log($"{carbonData.Count} Carbon data entities retrieved from SQL. Elapsed time: {sw.Elapsed}");

            return carbonData;
        }

        private void SaveCarbonData(List<CarbonData> carbonData)
        {
            var sw = Stopwatch.StartNew();

            var collection = GetCollection<CarbonData>();

            collection.Database.DropCollection(typeof(CarbonData).Name);

            collection.InsertMany(carbonData);

            var rowsAffected = collection.Count(new BsonDocument());

            sw.Stop();
            _syncContext.Log($"{rowsAffected} CarbonData entities saved. Elapsed time: {sw.Elapsed}");
        }

        private CarbonDataSqlRepository GetCarbonDataSqlRepository()
        {
            var carbonDataConnectionString = ConfigurationManager.ConnectionStrings["CarbonDataConnectionString"]?.ConnectionString;

            if (string.IsNullOrEmpty(carbonDataConnectionString))
                throw new ArgumentException("No connection string found for CarbonData!");

            var sqlDatabase = new CarbonDataSqlDatabase(carbonDataConnectionString, SyncHelper.ReadCommandTimeOutFromConfig());

            return CarbonDataSqlRepository.GetInstance(sqlDatabase);
        }

        private IMongoCollection<T> GetCollection<T>() where T : IEntity
        {
            var clientDWConnectionString = String.Empty;

            if (!_syncContext.GAConnectionStrings.TryGetValue("ClientDW", out clientDWConnectionString))
                throw new ArgumentException("No connection string found for ClientDW!");

            return MongoFactory.GetCollectionFromDatabase<T>(clientDWConnectionString);
        }
    }
}
